#ifndef __hex_hpp_lkjjwfejiojoiwef93323290i98u9hy7yf43jifejji2efjnvnjv__
#define __hex_hpp_lkjjwfejiojoiwef93323290i98u9hy7yf43jifejji2efjnvnjv__

#include <cstdint>
#include <string>
#include "base_type.hpp"
#include "optional.hpp"

namespace hude
{
    namespace utils
    {
        namespace details
        {
            /**********************************************************************************************
            * @brief _order_t
            */
            union _order_t
            {
                uint16_t v;

                uint64_t u8[1];
                uint32_t u4[2];
                uint16_t u2[4];
                uint8_t  u1[8];

                int64_t  s8[1];
                int32_t  s4[2];
                int16_t  s2[4];
                int8_t   s1[8];
            };

            /**********************************************************************************************
            * @brief get_item_t
            */
            template< typename _TYPE > struct _get_item_t {};

            template<> struct _get_item_t< uint64_t > { static uint64_t get( const _order_t& o ) { return o.u8[0]; } };
            template<> struct _get_item_t< uint32_t > { static uint32_t get( const _order_t& o ) { return o.u4[0]; } };
            template<> struct _get_item_t< uint16_t > { static uint16_t get( const _order_t& o ) { return o.u2[0]; } };

            template<> struct _get_item_t<  int64_t > { static  int64_t get( const _order_t& o ) { return o.s8[0]; } };
            template<> struct _get_item_t<  int32_t > { static  int32_t get( const _order_t& o ) { return o.s4[0]; } };
            template<> struct _get_item_t<  int16_t > { static  int16_t get( const _order_t& o ) { return o.s2[0]; } };

            /*********************************************************************
            * @brief 复制内容，如果目标类型是字节就直接赋值
            */
            template< typename _value, typename _byte >
            struct _value_copy_t
            {
                static inline void copy( _byte* d, const _byte* s )
                {
                    memcpy( d, s, sizeof( _value ) );
                }
            };

            template< typename _byte > struct _value_copy_t< uint8_t, _byte >
            {
                static inline void copy( _byte* d, const _byte* s ) { *d = *s; }
            };

            template< typename _byte > struct _value_copy_t<  int8_t, _byte >
            {
                static inline void copy( _byte* d, const _byte* s ) { *d = *s; }
            };
        } // namespace details

        /**********************************************************************************************
        * @brief 字节序转换
        */
        struct byte_order_t
        {
            enum type_t : uint8_t { emSMALL, emBIG, emNET = emBIG };

            /*********************************************************************
            * @brief 查询当前CPU的字节序
            */
            inline static type_t type()
            {
                return ( details::_order_t{ ( emBIG << 8 ) | emSMALL }.u1[0] == emSMALL )? emSMALL : emBIG;
            }

            /*********************************************************************
            * @brief 对指定地址的变量做字节序转换
            */
            template< type_t _TYPE, typename _OUTPUT >
            inline static void cast( const void* address, _OUTPUT& output )
            {
                cast_t< _TYPE >::cast( address, output );
            }

            /*********************************************************************
            * @brief 返回指定变量的字节序转换结果
            */
            template< type_t _TYPE, typename _VALUE >
            inline static _VALUE cast( _VALUE value )
            {
                _VALUE ret;

                cast_t< _TYPE >::cast( &value, ret );

                return ret;
            }

            /*********************************************************************
            * @brief 按指定的字节序做Get或Set操作
            */
            template< typename _target, byte_order_t::type_t _endless = byte_order_t::emNET >
            struct value_t
            {
                typedef _target target_t;

                inline static target_t order( target_t v ) { return byte_order_t::cast< _endless >( v ); }

                /*********************************************************************
                * @brief 从指定地址Get指定的类型
                */
                inline static target_t get( const void* p ) { target_t value; details::_value_copy_t< target_t, uint8_t >::copy( (uint8_t*)&value, (const uint8_t*)p ); return order( value ); }

                /*********************************************************************
                * @brief 向指定地址Set指定的类型
                */
                inline static void set( void* p, target_t value ) { value = order( value ); details::_value_copy_t< target_t, uint8_t >::copy( (uint8_t*)p, (const uint8_t*)&value ); }
            };

            /*********************************************************************
            * @brief 转换实现
            */
            template< type_t _TYPE > struct cast_t
            {
                enum { emTYPE_THIS = _TYPE };

                static void _cast( const uint8_t* address, uint8_t& output ) { output = (uint8_t)*address; }
                static void _cast( const uint8_t* address,  int8_t& output ) { output = ( int8_t)*address; }

                template< typename _OUTPUT >
                static void _cast( const uint8_t* address, _OUTPUT& output )
                {
                    details::_order_t o = { 0UL };

                    const unsigned int size = sizeof( output );

                    if( (type_t)emTYPE_THIS == type() )
                    {
                        for( unsigned int i = 0; i < size; ++i )
                        {
                            o.u1[ i ] = address[ i ];
                        }
                    } else {
                        for( unsigned int i = 0; i < size; ++i )
                        {
                            o.u1[ i ] = address[ (size - 1) - i ];
                        }
                    }
                    
                    output = details::_get_item_t< _OUTPUT >::get( o );
                }

                template< typename _OUTPUT >
                inline static void cast( const void* address, _OUTPUT& output )
                {
                    _cast( static_cast< const uint8_t * >( address ), output );
                }
            };
        };
        
        /**********************************************************************************************
        * @brief hash_t
        */
        template< typename _seed = std::size_t >
        struct hash_t
        {
            typedef _seed seed_t;
            seed_t seed;

            hash_t() : seed( 0U ) {}
            hash_t( seed_t s ) : seed( s ) {}

            template< typename _value >
            seed_t hash( const _value& v )
            {
                return seed = std::hash< _value >()( v ) + 0x9e3779b9 + ( seed << 6 ) + ( seed >> 2 );
            }

            template< typename _value, typename ... _args >
            seed_t hash( _value v, _args&& ... args )
            {
                hash( v );
                hash( std::forward< _args >( args ) ... );
                return seed;
            }

            template< typename ... _args >
            seed_t operator()( _args&& ... args )
            {
                return hash( std::forward< _args >( args ) ... );
            }

            operator seed_t() const { return seed; }
        };

        
        /**********************************************************************************************
        * @brief _to_hex
        */
        inline size_t _to_hex( const byte_t* bin, size_t siz, std::string& str, char spt = ' ' )
        {
            static const char *s = "0123456789abcdef";

            if ( siz == 0 )
            {
                str.clear();
                return 0;
            }

            if( spt == 0 )
            {
                str.resize( siz * 2 );

                for( size_t i = 0; i < siz; ++i )
                {
                    str[ (i*2) + 0 ] = s[ ( ( bin[i] >> 4 ) & 0x0f) ];
                    str[ (i*2) + 1 ] = s[ ( ( bin[i] >> 0 ) & 0x0f) ];
                }

                str[ siz * 2 ] = '\0';
            } else {
                str.resize( siz * 3 );

                for( size_t i = 0; i < siz; ++i )
                {
                    str[ (i*3) + 0 ] = s[ ( ( bin[i] >> 4 ) & 0x0f) ];
                    str[ (i*3) + 1 ] = s[ ( ( bin[i] >> 0 ) & 0x0f) ];
                    str[ (i*3) + 2 ] = spt;
                }

                str[ siz * 3 - 1 ] = '\0';
            }

            return str.length();
        }

        /***********************************************************************************************
        * @brief _from_hex
        */
        inline hude::optional_t< hude::buffer_t > _from_hex( const char* p, size_t n, char s = 0 )
        {
            auto hex = []( const char* p ) -> uint8_t
            {
                if( *p >= '0' && *p <= '9' )
                    return *p - '0';
                else if( *p >= 'a' && *p <= 'f' )
                    return *p - 'a' + 10;
                else if( *p >= 'A' && *p <= 'F' )
                    return *p - 'A' + 10;
                else
                    return 0xff;
            };

            assert( p != nullptr && n );

            auto c = n / 2;

            hude::buffer_t buffer( c );

            for( size_t i = 0; i < n; i += 2 )
            {
                if( s != 0 && *(p + i) == s ) { --i; continue; }

                auto h = hex( p + i );
                if( h == 0xff ) return hude::optional_null_t{};

                auto l = hex( p + i + 1 );
                if( l == 0xff ) return hude::optional_null_t{};

                buffer[ i / 2 ] = ( h << 4 ) | l;
            }

            return buffer;
        };
        
        /***********************************************************************************************
        * @brief 将二进制序列转换为十六进制字符串序列
        * @param bin: 二进制序列
        * @param siz: 要转换的二进制序列长度
        * @param str: 转换输出的十六进制字符串序列
        * @param spt: 输出序列字节间插入的分隔符，默认是空格，如果不需要插入则指定0
        * @return 转换输出的实际序列长度，包括分隔符。
        */
        inline size_t to_hex( const byte_t* bin, size_t siz, std::string& str, char spt = ' ' )
        {
            return _to_hex( bin, siz, str, spt );
        }

        /***********************************************************************************************
        * @brief 将二进制序列转换为十六进制字符串序列
        * @param bin: 二进制序列
        * @param siz: 要转换的二进制序列长度
        * @param spt: 输出序列字节间插入的分隔符，默认是空格，如果不需要插入则指定0
        * @return 返回转换后的十六进制序列
        */
        inline std::string to_hex( const byte_t* bin, size_t siz, char spt = ' ' )
        {
            std::string str;

            _to_hex( bin, siz, str, spt );

            return str;
        }

        /***********************************************************************************************
        * @brief 将二进制序列转换为十六进制字符串序列
        * @param bin: 存储二进制序列的缓存对象
        * @param siz: 要转换的二进制序列长度
        * @param str: 转换输出的十六进制字符串序列
        * @param spt: 输出序列字节间插入的分隔符，默认是空格，如果不需要插入则指定0
        * @return 转换输出的实际序列长度，包括分隔符。
        */
        inline size_t to_hex( const buffer_t& bin, std::string& str, size_t siz = 0, char spt = ' ' )
        {
            if ( siz != 0 || !bin.empty() )
            {
                return _to_hex( &( bin[0] ), ( siz == 0 ) ? bin.size() : siz, str, spt );
            } else {
                str.clear();
                return 0;
            }
        }

        /***********************************************************************************************
        * @brief 将二进制序列转换为十六进制字符串序列
        * @param bin: 二进制序列
        * @param siz: 要转换的二进制序列长度
        * @param spt: 输出序列字节间插入的分隔符，默认是空格，如果不需要插入则指定0
        * @return 返回转换后的十六进制序列
        */
        inline std::string to_hex( const buffer_t& bin, size_t siz = 0, char spt = ' ' )
        {
            std::string str;

            if ( siz != 0 || !bin.empty() )
            {
                _to_hex( &(bin[0]), (siz == 0)? bin.size() : siz, str, spt );
            }

            return str;
        }

        /***********************************************************************************************
        * @brief 将十六进制字符串序列转换为二进制序列
        * @param p: 十六进制字符串
        * @param n: 要转换的十六进制序列的字符串长度
        * @param s: 指定忽略十六进制字符串序列中存在的间隔符
        * @return 返回optional_t类型的转换结果，如果转换成功则其包含转换后的二进制序，否则optional_t为空
        */
        inline hude::optional_t< hude::buffer_t > from_hex( const char* p, size_t n, char s = 0 )
        {
            return _from_hex( p, n, s );
        }

        /***********************************************************************************************
        * @brief 将十六进制字符串序列转换为二进制序列
        * @param str: 十六进制字符串
        * @param spt: 指定忽略十六进制字符串序列中存在的间隔符
        * @return 返回optional_t类型的转换结果，如果转换成功则其包含转换后的二进制序，否则optional_t为空
        */
        inline hude::optional_t< hude::buffer_t > from_hex( const std::string& str, char spt = 0 )
        {
            return _from_hex( &(str[0]), str.size(), spt );
        }

    } //namespace utils
} //namespace hude

#endif //__hex_hpp_lkjjwfejiojoiwef93323290i98u9hy7yf43jifejji2efjnvnjv__

